2009 年,WHO 在八個國家的醫院推行了一份手術安全檢查表。19 個勾選項,從「確認病人身份」到「術後器械清點」。Atul Gawande 帶領的研究團隊在 New England Journal of Medicine 發表結果:術後併發症下降超過三分之一,死亡率幾乎減半。
不是因為外科醫生變厲害了。是因為他們不再跳步驟。
再厲害的醫生也會漏。不是技術不夠,是忙起來會忘。Checklist 做的不是教你怎麼開刀,是確保每次開刀都跑完該跑的步驟。
軟體開發在 2006 年學到了同一件事。
Martin Fowler 在 2006 年發表了一篇後來被大量引用的文章:"Continuous Integration"。他描述的問題叫 integration hell — 團隊各寫各的,等到要合併的時候才發現接口對不上、版本衝突、測試一片紅。合併那天是專案裡最痛苦的一天。
CI 的解法:不要等。每次 commit 都跑一遍自動檢查 — lint、compile、test。問題在進去的那一刻被抓到,不是累積三週後一次爆開。
CI 不是什麼高深技術。它就是一份自動跑的 checklist:code style 對了沒?型別對了沒?測試過了沒?三個都過了才算 commit 成功。
Day 6 講了用測試驗證 AI 產出的 code 行為是否正確。但測試是三道關卡裡的一道,不是全部。
一段 code 可以測試全過,但有 lint 警告 — 用了 deprecated API、import 順序亂了、有未使用的變數。這些東西人在 review 的時候會順手挑出來,AI 沒被要求的話不一定會去查。
一段 code 可以測試全過,但型別檢查沒跑 — 型別用 any 寫出來的東西 runtime 會動,下游拿到的卻不是預期的型別。
一段 code 可以測試全過,但 commit 裡混進了一個 .env 檔。
測試驗證行為。Lint 驗證慣例。Type check 驗證結構。三道關卡抓的東西不一樣,缺一道就少一層保護。
AI 比人更需要這三道關卡,原因很直接:AI 的預設行為是「做到你要求的那件事」。要求它讓測試通過,它就讓測試通過。沒要求它跑 lint,它就不跑。沒要求它檢查型別,它就不檢查。人會因為經驗和習慣順手做這些事。AI 的習慣是你定義的。
第一步通常是在 CLAUDE.md 裡寫一條規則 —「commit 前跑三件事:lint、typecheck、test。三個都過才 commit。」Day 3 把這種做法叫適應式指令 — 只給判斷依據,不規定每一步怎麼做。Agent 會自己根據專案工具跑 ruff check 或 eslint、跑 tsc -b 或 mypy、跑 pytest 或 vitest。
問題是 CLAUDE.md 不保證每次都被讀到。Context window 塞滿的時候、長對話壓縮之後、或是 agent 拆了子任務,這條規則可能剛好不在 agent 看到的範圍裡。大部分時候有用,但「大部分時候」不夠 — 爛 code 混進 main branch 只需要漏一次。
Claude Code 的 hooks 能做到這件事。Hook 是在 agent 執行特定動作前後自動觸發的腳本 — 比如在 agent 要跑 git commit 之前,先攔截,跑完 lint + typecheck + test,全過了才放行。Agent 沒辦法繞過,因為 hook 不是建議,是閘門。
效果等同於把 CI pipeline 從遠端的 GitHub Actions 搬到本地的 agent loop 裡。傳統流程是:寫 code → push → CI 跑五分鐘 → 紅燈 → 改 → push → 再跑五分鐘。用 hook 之後:agent 寫 code → hook 攔截 → 幾秒跑完 → 紅燈 → agent 立刻改 → 再跑 → 綠燈 → commit。回饋時間從分鐘級變秒級。
Day 6 的 /loop 把「跑測試到全過」變成一條指令。Hook 把「commit 前跑完所有檢查」變成一道不用記的閘門。兩個搭起來,agent 的每次 commit 都經過完整驗收 — 三個綠燈才放行。
Gawande 在 The Checklist Manifesto 裡寫了一句話:「在複雜的條件下,checklist 不只是輔助,它是成功的必要條件。」
他說的是手術。但軟體工程在 2006 年用 CI 印證了同一件事。2026 年,AI coding agent 又印證了一次。
問題從來不是執行者夠不夠聰明。外科醫生夠聰明,還是會漏。資深工程師夠聰明,還是會漏。AI 夠聰明 — 也還是會漏。
Checklist 存在的原因不是不信任執行者。是因為「不會漏」跟「不能漏」是兩回事。CI 就是軟體的那份手術安全檢查表。
延伸閱讀